/**
 * 测试epoll函数的使用，默认LT模式；
 * @author: sundx
 * @date: 2020-06-01 18:15:53
 * @Last Modified by: sundx
 * @Last Modified time: 2020-06-01 18:16:17
 */
#include "wrap.h"
#include <iostream>
#define OPEN_MAX 5800

int main() {
  int listenFd = sdx::serverSocketBindListen();
  epoll_event listenFdEvent, allEvents[OPEN_MAX];
  sockaddr_in clientAddr;
  socklen_t clientAddrLen = sizeof(clientAddr);
  listenFdEvent.events = EPOLLIN;
  listenFdEvent.data.fd = listenFd;
  int epollRoot = sdx::Epoll_create(20); // 创建epoll红黑树
  //添加listenfd到红黑树；
  sdx::Epoll_ctl(epollRoot, EPOLL_CTL_ADD, listenFd, &listenFdEvent);

  while (1) {
    int activeFd = sdx::Epoll_wait(epollRoot, allEvents, OPEN_MAX, -1);

    for (int i = 0; i < activeFd; ++i) {
      if (!(allEvents[i].events) && EPOLLIN) // 如果不是读事件，进入下一循坏
        continue;
      if (allEvents[i].data.fd == listenFd) { //如果是监听触发，则建立新连接
        char clientAddrChar[INET_ADDRSTRLEN];
        bzero(clientAddrChar, INET_ADDRSTRLEN);
        int connFd =
            sdx::Accept(listenFd, (sockaddr *)&clientAddr, &clientAddrLen);
        std::cout << inet_ntop(AF_INET, &clientAddr.sin_addr, clientAddrChar,
                               INET_ADDRSTRLEN)
                  << " " << ntohs(clientAddr.sin_port) << std::endl;
        listenFdEvent.data.fd = connFd; //这里使用之前listenFd用的结构体也可以
        listenFdEvent.events = EPOLLIN; //为啥呢？？
        // 挂到红黑树上；
        sdx::Epoll_ctl(epollRoot, EPOLL_CTL_ADD, connFd, &listenFdEvent);
      } else { //是通信fd；
        int cnnFd = allEvents[i].data.fd;
        char inbuff[MESSAGE_SIZE];   //读缓冲区
        bzero(inbuff, MESSAGE_SIZE); //初始化缓冲区
        int recvBytes = recv(cnnFd, inbuff, MESSAGE_SIZE, 0);
        if (recvBytes == 0) { //判断是否是客户端关闭
          std::cout << " close the connect..." << std::endl;
          close(cnnFd);
        } else if (recvBytes > 0) {
          std::cout << "receive " << recvBytes << " bytes message from "
                    << ", and the message is " << inbuff << std::endl;

          for (int j = 0; j < recvBytes; ++j) { // 小写转大写listenFdEvent
            inbuff[j] = toupper(inbuff[j]);
          }

          int ret = send(cnnFd, inbuff, recvBytes, 0); //发送
          if (ret == -1) {
            sdx::printError("recv failed");
          }

        } else { //判断是否出错；
          if ((errno == ECONNABORTED) || (errno == EINTR)) {
            continue;
          } else {
            sdx::printError("recv error...");
          }
        }
      }
    }
  }
  close(listenFd);
  close(epollRoot);
  return 0;
}
